package org.example.visualization;

import org.example.domain.CuttingPlanSolution;
import org.example.domain.CuttingSpot;
import org.example.domain.RectangularPiece;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.AffineTransform;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;

public class CuttingVisualizer extends JFrame {
    private static final int PADDING = 40;
    private double scale = 1.0;
    private static final double ZOOM_FACTOR = 1.1;
    private int currentPage = 0;
    private final CuttingPlanSolution solution;
    private final Map<Long, Color> pieceColors;
    private final CuttingPanel cuttingPanel;
    private final JLabel scaleLabel;
    private final JLabel statsLabel;
    private final JLabel pageLabel;
    private Point lastMousePos;

    public CuttingVisualizer(CuttingPlanSolution solution) {
        this.solution = solution;
        this.pieceColors = generatePieceColors(solution);
        
        setTitle("切割方案可视化");
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        
        // 创建主面板
        JPanel mainPanel = new JPanel(new BorderLayout());
        
        // 创建顶部工具栏面板
        JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
        
        // 添加缩放控制按钮
        JButton zoomInButton = new JButton("+");
        JButton zoomOutButton = new JButton("-");
        JButton resetButton = new JButton("重置缩放");
        scaleLabel = new JLabel("缩放: 100%");
        
        zoomInButton.addActionListener(e -> changeScale(ZOOM_FACTOR));
        zoomOutButton.addActionListener(e -> changeScale(1/ZOOM_FACTOR));
        resetButton.addActionListener(e -> resetScale());
        
        topPanel.add(zoomInButton);
        topPanel.add(zoomOutButton);
        topPanel.add(resetButton);
        topPanel.add(scaleLabel);
        
        // 添加统计信息标签
        statsLabel = new JLabel();
        updateStatsLabel();
        topPanel.add(Box.createHorizontalStrut(20));
        topPanel.add(statsLabel);
        
        mainPanel.add(topPanel, BorderLayout.NORTH);
        
        // 创建中间的切割面板
        cuttingPanel = new CuttingPanel();
        JScrollPane scrollPane = new JScrollPane(cuttingPanel);
        mainPanel.add(scrollPane, BorderLayout.CENTER);
        
        // 创建底部导航面板
        JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
        JButton prevButton = new JButton("上一页");
        JButton nextButton = new JButton("下一页");
        pageLabel = new JLabel(String.format("板料 %d/%d", 
                currentPage + 1, solution.getStockPieces().size()));
        
        prevButton.addActionListener(e -> changePage(false));
        nextButton.addActionListener(e -> changePage(true));
        
        bottomPanel.add(prevButton);
        bottomPanel.add(pageLabel);
        bottomPanel.add(nextButton);
        
        mainPanel.add(bottomPanel, BorderLayout.SOUTH);
        
        // 添加图例面板
        mainPanel.add(new LegendPanel(), BorderLayout.EAST);
        
        add(mainPanel);
        
        // 设置窗口最大化
        setExtendedState(JFrame.MAXIMIZED_BOTH);
        
        // 添加鼠标事件监听
        cuttingPanel.addMouseWheelListener(e -> {
            if (e.isControlDown()) {
                Point mousePoint = e.getPoint();
                if (e.getWheelRotation() < 0) {
                    zoomAtPoint(mousePoint, ZOOM_FACTOR);
                } else {
                    zoomAtPoint(mousePoint, 1/ZOOM_FACTOR);
                }
                e.consume();
            }
        });
        
        // 添加鼠标拖动支持
        cuttingPanel.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                lastMousePos = e.getPoint();
                cuttingPanel.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
            }
            
            @Override
            public void mouseReleased(MouseEvent e) {
                cuttingPanel.setCursor(Cursor.getDefaultCursor());
            }
        });
        
        cuttingPanel.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                if (lastMousePos != null) {
                    JViewport viewport = (JViewport) cuttingPanel.getParent();
                    Point currentPos = e.getPoint();
                    Point viewPos = viewport.getViewPosition();
                    
                    viewPos.translate(lastMousePos.x - currentPos.x, 
                                    lastMousePos.y - currentPos.y);
                    
                    cuttingPanel.scrollRectToVisible(new Rectangle(viewPos, viewport.getSize()));
                    lastMousePos = currentPos;
                }
            }
        });
    }

    private void updateStatsLabel() {
        long usedStocks = solution.getCuttingSpots().stream()
                .map(CuttingSpot::getStock)
                .distinct()
                .count();
        int totalPieces = solution.getCuttingSpots().size();
        statsLabel.setText(String.format("使用板料数: %d | 零件数: %d | 得分: %s", 
                usedStocks, totalPieces, solution.getScore()));
    }

    private void changeScale(double factor) {
        double newScale = scale * factor;
        if (newScale >= 0.1 && newScale <= 10.0) {
            scale = newScale;
            scaleLabel.setText(String.format("缩放: %.0f%%", scale * 100));
            cuttingPanel.revalidate();
            cuttingPanel.repaint();
        }
    }

    private void resetScale() {
        scale = 1.0;
        scaleLabel.setText("缩放: 100%");
        cuttingPanel.revalidate();
        cuttingPanel.repaint();
    }

    private void changePage(boolean next) {
        if (next && currentPage < solution.getStockPieces().size() - 1) {
            currentPage++;
        } else if (!next && currentPage > 0) {
            currentPage--;
        }
        pageLabel.setText(String.format("板料 %d/%d", 
                currentPage + 1, solution.getStockPieces().size()));
        cuttingPanel.repaint();
    }

    private Map<Long, Color> generatePieceColors(CuttingPlanSolution solution) {
        Random random = new Random(1234);
        return solution.getDemandPieces().stream()
                .collect(Collectors.toMap(
                        RectangularPiece::getId,
                        piece -> new Color(
                                0.3f + random.nextFloat() * 0.4f,
                                0.3f + random.nextFloat() * 0.4f,
                                0.3f + random.nextFloat() * 0.4f
                        )
                ));
    }

    private void zoomAtPoint(Point p, double factor) {
        if ((scale * factor >= 0.1) && (scale * factor <= 10.0)) {
            JViewport viewport = (JViewport) cuttingPanel.getParent();
            Point viewPos = viewport.getViewPosition();
            
            // 计算鼠标位置相对于视口的比例
            double relativeX = (p.x + viewPos.x) / (double) cuttingPanel.getWidth();
            double relativeY = (p.y + viewPos.y) / (double) cuttingPanel.getHeight();
            
            // 应用缩放
            changeScale(factor);
            
            // 调整视口位置，使缩放中心保持在鼠标位置
            viewport.setViewPosition(new Point(
                (int) (cuttingPanel.getWidth() * relativeX - p.x),
                (int) (cuttingPanel.getHeight() * relativeY - p.y)
            ));
        }
    }

    class CuttingPanel extends JPanel {
        public static final Color SAW_GAP_COLOR = new Color(255, 0, 0, 50);
        private static final int SAW_WIDTH = 2;

        @Override
        public Dimension getPreferredSize() {
            RectangularPiece stock = solution.getStockPieces().get(currentPage);
            return new Dimension(
                    (int)(stock.getWidth() * scale) + PADDING * 2,
                    (int)(stock.getHeight() * scale) + PADDING * 2
            );
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                    RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, 
                    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

            // 应用缩放变换
            AffineTransform originalTransform = g2d.getTransform();
            g2d.translate(PADDING, PADDING);
            g2d.scale(scale, scale);

            // 绘制当前页的板料
            RectangularPiece stock = solution.getStockPieces().get(currentPage);
            
            // 绘制板料边框
            g2d.setColor(Color.BLACK);
            g2d.drawRect(0, 0, stock.getWidth(), stock.getHeight());

            // 绘制板料信息
            g2d.setTransform(originalTransform);
            g2d.drawString(String.format("板料 %d (%dx%d)", 
                    stock.getId(), stock.getWidth(), stock.getHeight()), 
                    PADDING, PADDING - 5);
            g2d.setTransform(originalTransform);
            g2d.translate(PADDING, PADDING);
            g2d.scale(scale, scale);

            // 绘制零件
            List<CuttingSpot> spotsOnStock = solution.getCuttingSpots().stream()
                    .filter(spot -> stock.equals(spot.getStock()))
                    .collect(Collectors.toList());
            
            for (CuttingSpot spot : spotsOnStock) {
                drawPiece(g2d, spot);
            }

            // 恢复原始变换
            g2d.setTransform(originalTransform);
        }

        private void drawPiece(Graphics2D g2d, CuttingSpot spot) {
            RectangularPiece piece = spot.getPiece();
            g2d.setColor(pieceColors.get(piece.getId()));
            
            // 填充零件区域
            g2d.fillRect(spot.getX(), spot.getY(), 
                    piece.getWidth(), piece.getHeight());
            
            // 绘制零件边框
            g2d.setColor(Color.BLACK);
            g2d.drawRect(spot.getX(), spot.getY(), 
                    piece.getWidth(), piece.getHeight());
            
            // 绘制零件信息
            // 保存当前字体大小
            Font originalFont = g2d.getFont();
            // 根据缩放调整字体大小
            g2d.setFont(new Font(originalFont.getName(), 
                    originalFont.getStyle(), 
                    (int)(12 / scale)));
            
            String pieceInfo = String.format("%d\n%dx%d", 
                    piece.getId(), piece.getWidth(), piece.getHeight());
            drawCenteredString(g2d, pieceInfo,
                    spot.getX(), spot.getY(),
                    piece.getWidth(), piece.getHeight());
            
            // 恢复原始字体
            g2d.setFont(originalFont);
        }

        private void drawCenteredString(Graphics2D g2d, String text, int x, int y, int width, int height) {
            FontMetrics fm = g2d.getFontMetrics();
            String[] lines = text.split("\n");
            int lineHeight = fm.getHeight();
            int totalHeight = lines.length * lineHeight;
            int currentY = y + (height - totalHeight) / 2 + fm.getAscent();

            for (String line : lines) {
                int stringWidth = fm.stringWidth(line);
                int startX = x + (width - stringWidth) / 2;
                g2d.drawString(line, startX, currentY);
                currentY += lineHeight;
            }
        }
    }

    class LegendPanel extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                    RenderingHints.VALUE_ANTIALIAS_ON);

            int x = 10;
            int y = 20;
            int boxSize = 15;

            g2d.drawString("图例:", x, y);
            y += 25;

            // 零件图例
            for (RectangularPiece piece : solution.getDemandPieces()) {
                g2d.setColor(pieceColors.get(piece.getId()));
                g2d.fillRect(x, y, boxSize, boxSize);
                g2d.setColor(Color.BLACK);
                g2d.drawRect(x, y, boxSize, boxSize);
                g2d.drawString(
                        String.format("零件 %d (%dx%d)", 
                                piece.getId(), 
                                piece.getWidth(), 
                                piece.getHeight()),
                        x + boxSize + 5,
                        y + boxSize
                );
                y += 25;
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, getHeight());
        }
    }
} 